From: tsteven4 Date: Sat, 9 Feb 2019 21:59:09 +0000 (-0700) Subject: Introduce a RouteList class. X-Git-Tag: archive/raspbian/1.10.0+ds-2+rpi1~1^2~12^2~8^2~22^2~4 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https://%22%22/%22http:/www.example.com/cgi/%22https:/%22%22?a=commitdiff_plain;h=79452b09f42073d7de513270b2cd188302edbdf9;p=gpsbabel.git Introduce a RouteList class. This is backed by a QueueList class, which adds iterators for queues. It is anticipated that this will be replaced by usage of a more standard container. --- diff --git a/bend.cc b/bend.cc index 38c2e0456..d794ee1d6 100644 --- a/bend.cc +++ b/bend.cc @@ -44,7 +44,7 @@ void BendFilter::init() minAngle = strtod(minangleopt, nullptr); } - route_backup(&routes_orig_num, &routes_orig); + route_backup(&routes_orig); route_flush_all_routes(); } @@ -158,17 +158,17 @@ void BendFilter::process_route_orig(const route_head* route_orig) void BendFilter::process() { - queue* elem, *tmp; - QUEUE_FOR_EACH(routes_orig, elem, tmp) { - route_head* route_orig = reinterpret_cast(elem); + for (auto it = routes_orig->cbegin(); it != routes_orig->cend(); ++it) { + auto route_orig = reinterpret_cast(*it); process_route_orig(route_orig); } } void BendFilter::deinit() { - route_flush(routes_orig); - xfree(routes_orig); + routes_orig->flush(); + delete routes_orig; + routes_orig = nullptr; } #endif // FILTERS_ENABLED diff --git a/bend.h b/bend.h index 242d0f78d..904c02999 100644 --- a/bend.h +++ b/bend.h @@ -47,8 +47,7 @@ private: double maxDist; double minAngle; - queue* routes_orig = nullptr; - int routes_orig_num = 0; + RouteList* routes_orig = nullptr; arglist_t args[3] = { { diff --git a/defs.h b/defs.h index e7221ce3a..b9710d6e6 100644 --- a/defs.h +++ b/defs.h @@ -609,7 +609,7 @@ waypt_disp_session(const session_t* se, T cb) #else queue* elem, *tmp; QUEUE_FOR_EACH(&waypt_head, elem, tmp) { - Waypoint* waypointp = reinterpret_cast(elem); + Waypoint* waypointp = reinterpret_cast(elem); #endif if ((se == nullptr) || (waypointp->session == se)) { if (global_opts.verbose_status) { @@ -667,12 +667,74 @@ public: public: route_head(); + // the default copy constructor and assignment operator are not appropriate as we do deep copy of some members, + // and we haven't bothered to write an appropriate one. + // Catch attempts to use the default copy constructor and assignment operator. + route_head(const route_head& other) = delete; + route_head& operator=(const route_head& rhs) = delete; ~route_head(); }; typedef void (*route_hdr)(const route_head*); typedef void (*route_trl)(const route_head*); +// TODO: Consider using composition instead of private inheritance. +class RouteList : private QueueList +{ +public: +// FIXME: The interface should NOT depend on the implementation of the list. +// Migrate to std::sort using a compare function +// typedef bool (*Compare)(const route_head* a, const route_head* b); + typedef int (*Compare)(const queue* a, const queue* b); + + RouteList(); + + int count() const; // a.k.a. size() + int waypt_count() const; + void add_head(route_head* rte); // a.k.a. append(), push_back() + // FIXME: Generally it is inefficient to use an element pointer or reference to define the element to be deleted, use iterator instead, + // and/or implement pop_back() a.k.a. removeLast(), and/or pop_front() a.k.a. removeFirst(). + void del_head(route_head* rte); // a.k.a. erase() + // FIXME: Generally it is inefficent to use an element pointer or reference to define the insertion point, use iterator instead. + void insert_head(route_head* rte, route_head* predecessor); // a.k.a. insert + void add_wpt(route_head* rte, Waypoint* wpt, bool synth, const QString& namepart, int number_digits); + // FIXME: Generally it is inefficent to use an element pointer or reference to define the insertion point, use iterator instead. + void del_wpt(route_head* rte, Waypoint* wpt); + void common_disp_session(const session_t* se, route_hdr rh, route_trl rt, waypt_cb wc); + void flush(); // a.k.a. clear() + void copy(RouteList** dst) const; + void restore(RouteList* src); + void swap(RouteList& other); + void sort(Compare cmp); + template + void disp_all(T1 rh, T2 rt, T3 wc); + template + void disp_all(std::nullptr_t /* rh */, T2 rt, T3 wc); + template + void disp_all(T1 rh, std::nullptr_t /* rt */, T3 wc); + template + void disp_all(std::nullptr_t /* rh */, std::nullptr_t /* rt */, T3 wc); + + // Only expose methods from our underlying container that won't corrupt our private data. + // Our contained element (route_head) also contains a container (waypoint_list), + // and we maintain a total count the elements in these contained containers, i.e. + // the total number of waypoints in all the routes in the RouteList. + using QueueList::begin; + using QueueList::end; + using QueueList::cbegin; + using QueueList::cend; + using QueueList::empty; // a.k.a. isEmpty() + using QueueList::front; // a.k.a. first() + using QueueList::back; // a.k.a. last() + using QueueList::Iterator; + using QueueList::ConstIterator; + +private: + queue head; + int head_ct{0}; + int waypt_ct{0}; +}; + void route_init(); unsigned int route_waypt_count(); unsigned int route_count(); @@ -684,13 +746,8 @@ void route_del_head(route_head* rte); void track_add_head(route_head* rte); void track_del_head(route_head* rte); void track_insert_head(route_head* rte, route_head* predecessor); -route_head* route_find_route_by_name(const char* name); -route_head* route_find_track_by_name(const char* name); -void route_add_wpt_named(route_head* rte, Waypoint* wpt, const QString& namepart, int number_digits); -void route_add_wpt(route_head* rte, Waypoint* wpt); -void track_add_wpt_named(route_head* rte, Waypoint* wpt, const QString& namepart, int number_digits); -void track_add_wpt(route_head* rte, Waypoint* wpt); -Waypoint* route_find_waypt_by_name(route_head* rh, const char* name); +void route_add_wpt(route_head* rte, Waypoint* wpt, const QString& namepart = "RPT", int number_digits = 3); +void track_add_wpt(route_head* rte, Waypoint* wpt, const QString& namepart = "RPT", int number_digits = 3); void route_del_wpt(route_head* rte, Waypoint* wpt); void track_del_wpt(route_head* rte, Waypoint* wpt); //void route_disp(const route_head* rte, waypt_cb); /* template */ @@ -702,15 +759,17 @@ void route_disp_session(const session_t* se, route_hdr rh, route_trl rt, waypt_c void track_disp_session(const session_t* se, route_hdr rh, route_trl rt, waypt_cb wc); void route_flush_all_routes(); void route_flush_all_tracks(); -void route_flush_all(); -void route_flush(queue* head); -void route_copy(int* dst_count, int* dst_wpt_count, queue** dst, queue* src); -void route_append(queue* src); -void track_append(queue* src); -void route_backup(signed int* count, queue** head_bak); -void route_restore(queue* head_bak); -void track_backup(signed int* count, queue** head_bak); -void track_restore(queue* head_bak); +void route_deinit(); +void route_append(RouteList* src); +void track_append(RouteList* src); +void route_backup(RouteList** head_bak); +void route_restore(RouteList* head_bak); +void route_swap(RouteList& other); +void route_sort(RouteList::Compare cmp); +void track_backup(RouteList** head_bak); +void track_restore(RouteList* head_bak); +void track_swap(RouteList& other); +void track_sort(RouteList::Compare cmp); computed_trkdata track_recompute(const route_head* trk); template @@ -721,19 +780,19 @@ route_disp(const route_head* rh, T cb) // cb != nullptr, caught with an overload of route_disp QUEUE_FOR_EACH(&rh->waypoint_list, elem, tmp) { Waypoint* waypointp; - waypointp = reinterpret_cast(elem); + waypointp = reinterpret_cast(elem); cb(waypointp); } } template void -common_disp_all(queue* qh, T1 rh, T2 rt, T3 wc) +RouteList::disp_all(T1 rh, T2 rt, T3 wc) { queue* elem, *tmp; - QUEUE_FOR_EACH(qh, elem, tmp) { + QUEUE_FOR_EACH(&head, elem, tmp) { const route_head* rhp; - rhp = reinterpret_cast(elem); + rhp = reinterpret_cast(elem); // rh != nullptr, caught with an overload of common_disp_all rh(rhp); route_disp(rhp, wc); @@ -744,12 +803,12 @@ common_disp_all(queue* qh, T1 rh, T2 rt, T3 wc) template void -common_disp_all(queue* qh, std::nullptr_t /* rh */, T2 rt, T3 wc) +RouteList::disp_all(std::nullptr_t /* rh */, T2 rt, T3 wc) { queue* elem, *tmp; - QUEUE_FOR_EACH(qh, elem, tmp) { + QUEUE_FOR_EACH(&head, elem, tmp) { const route_head* rhp; - rhp = reinterpret_cast(elem); + rhp = reinterpret_cast(elem); // rh == nullptr route_disp(rhp, wc); // rt != nullptr, caught with an overload of common_disp_all @@ -759,12 +818,12 @@ common_disp_all(queue* qh, std::nullptr_t /* rh */, T2 rt, T3 wc) template void -common_disp_all(queue* qh, T1 rh, std::nullptr_t /* rt */, T3 wc) +RouteList::disp_all(T1 rh, std::nullptr_t /* rt */, T3 wc) { queue* elem, *tmp; - QUEUE_FOR_EACH(qh, elem, tmp) { + QUEUE_FOR_EACH(&head, elem, tmp) { const route_head* rhp; - rhp = reinterpret_cast(elem); + rhp = reinterpret_cast(elem); // rh != nullptr, caught with an overload of common_disp_all rh(rhp); route_disp(rhp, wc); @@ -774,12 +833,12 @@ common_disp_all(queue* qh, T1 rh, std::nullptr_t /* rt */, T3 wc) template void -common_disp_all(queue* qh, std::nullptr_t /* rh */, std::nullptr_t /* rt */, T3 wc) +RouteList::disp_all(std::nullptr_t /* rh */, std::nullptr_t /* rt */, T3 wc) { queue* elem, *tmp; - QUEUE_FOR_EACH(qh, elem, tmp) { + QUEUE_FOR_EACH(&head, elem, tmp) { const route_head* rhp; - rhp = reinterpret_cast(elem); + rhp = reinterpret_cast(elem); // rh == nullptr route_disp(rhp, wc); // rt == nullptr @@ -790,18 +849,18 @@ template void route_disp_all(T1 rh, T2 rt, T3 wc) { - extern queue my_route_head; + extern RouteList* global_route_list; - common_disp_all(&my_route_head, rh, rt, wc); + global_route_list->disp_all(rh, rt, wc); } template void track_disp_all(T1 rh, T2 rt, T3 wc) { - extern queue my_track_head; + extern RouteList* global_track_list; - common_disp_all(&my_track_head, rh, rt, wc); + global_track_list->disp_all(rh, rt, wc); } typedef struct { @@ -1184,7 +1243,7 @@ double fmt_speed(double, const char** tag); /* * From nmea.c */ -int nmea_cksum(const char*buf); +int nmea_cksum(const char* buf); /* * Color helpers. diff --git a/interpolate.cc b/interpolate.cc index 92ea66573..fa8933fc8 100644 --- a/interpolate.cc +++ b/interpolate.cc @@ -30,28 +30,27 @@ void InterpolateFilter::process() { - queue* backuproute = nullptr; - queue* elem, *tmp, *elem2, *tmp2; - int count = 0; + RouteList* backuproute = nullptr; + queue* elem2, *tmp2; double lat1 = 0, lon1 = 0; double altitude1 = unknown_alt; unsigned int time1 = 0; double frac; if (opt_route) { - route_backup(&count, &backuproute); + route_backup(&backuproute); route_flush_all_routes(); } else { - track_backup(&count, &backuproute); + track_backup(&backuproute); route_flush_all_tracks(); } - if (count == 0) { + if (backuproute->empty()) { fatal(MYNAME ": Found no routes or tracks to operate on.\n"); } - QUEUE_FOR_EACH(backuproute, elem, tmp) { - route_head* rte_old = reinterpret_cast(elem); + for (auto it = backuproute->cbegin(); it != backuproute->cend(); ++it) { + auto rte_old = reinterpret_cast(*it); route_head* rte_new = route_head_alloc(); rte_new->rte_name = rte_old->rte_name; @@ -139,8 +138,8 @@ void InterpolateFilter::process() time1 = wpt->creation_time.toTime_t(); } } - route_flush(backuproute); - xfree(backuproute); + backuproute->flush(); + delete backuproute; } void InterpolateFilter::init() diff --git a/main.cc b/main.cc index 8990f1a24..eb869e252 100644 --- a/main.cc +++ b/main.cc @@ -213,8 +213,10 @@ main(int argc, char* argv[]) int opt_version = 0; int did_something = 0; const char* prog_name = argv[0]; /* argv is modified during processing */ - queue* wpt_head_bak, *rte_head_bak, *trk_head_bak; /* #ifdef UTF8_SUPPORT */ - signed int wpt_ct_bak, rte_ct_bak, trk_ct_bak; /* #ifdef UTF8_SUPPORT */ + queue* wpt_head_bak; /* #ifdef UTF8_SUPPORT */ + RouteList* rte_head_bak, *trk_head_bak; /* #ifdef UTF8_SUPPORT */ + signed int wpt_ct_bak; /* #ifdef UTF8_SUPPORT */ + bool lists_backedup; /* #ifdef UTF8_SUPPORT */ QStack qargs_stack = QStack(); // Create a QCoreApplication object to handle application initialization. @@ -401,9 +403,7 @@ main(int argc, char* argv[]) cet_convert_init(ovecs->encode, ovecs->fixed_encode); - wpt_ct_bak = -1; - rte_ct_bak = -1; - trk_ct_bak = -1; + lists_backedup = false; rte_head_bak = trk_head_bak = nullptr; ovecs->wr_init(ofname); @@ -417,9 +417,10 @@ main(int argc, char* argv[]) */ int saved_status = global_opts.verbose_status; global_opts.verbose_status = 0; + lists_backedup = true; waypt_backup(&wpt_ct_bak, &wpt_head_bak); - route_backup(&rte_ct_bak, &rte_head_bak); - track_backup(&trk_ct_bak, &trk_head_bak); + route_backup(&rte_head_bak); + track_backup(&trk_head_bak); cet_convert_strings(nullptr, global_opts.charset, nullptr); global_opts.verbose_status = saved_status; @@ -430,16 +431,12 @@ main(int argc, char* argv[]) cet_convert_deinit(); - if (wpt_ct_bak != -1) { + if (lists_backedup) { waypt_restore(wpt_ct_bak, wpt_head_bak); - } - if (rte_ct_bak != -1) { route_restore(rte_head_bak); - xfree(rte_head_bak); - } - if (trk_ct_bak != -1) { + delete rte_head_bak; track_restore(trk_head_bak); - xfree(trk_head_bak); + delete trk_head_bak; } } break; @@ -720,7 +717,7 @@ main(int argc, char* argv[]) cet_deregister(); waypt_flush_all(); - route_flush_all(); + route_deinit(); session_exit(); exit_vecs(); exit_filter_vecs(); diff --git a/queue.h b/queue.h index 860239ee5..cab0c2961 100644 --- a/queue.h +++ b/queue.h @@ -21,6 +21,8 @@ #ifndef QUEUE_H_INCLUDED_ #define QUEUE_H_INCLUDED_ +#include + typedef struct queue { struct queue* next; struct queue* prev; @@ -61,6 +63,197 @@ queue* dequeue(queue* element); (element) != (listhead); \ (element) = (tmp)) +// FIXME: g++ 7.3.0, -O2, with T=route_head yields warnings. +// implementing QueueList as a template was meant to +// i) avoid reinterpret_casts all over the code as with QUEUE_FOR_EACH +// ii) allow use of range based for loops. +// If this isn't fixed then QueueList doesn't need to be a template, T == queue. +// In file included from defs.h:27:0, +// from bend.cc:23: +// queue.h: In instantiation of ‘const T*& QueueList::ConstIterator::operator*() [with T = route_head; QueueList::ConstIterator::reference = const route_head*&]’: +// bend.cc:162:24: required from here +// queue.h:143:14: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] +// return reinterpret_cast(ptr_); +// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +template +class QueueList +{ +public: + + QueueList(queue* head, int* ct) : head_{head}, ct_{ct} {} + + class Iterator + { + public: + using iterator_category = std::bidirectional_iterator_tag; + using value_type = T*; + using difference_type = std::ptrdiff_t; + using pointer = T** ; + using reference = T* &; + + Iterator() = default; + explicit Iterator(queue* p) : ptr_{p} {} + + reference operator*() + { + return reinterpret_cast(ptr_); + } + pointer operator->() + { + return reinterpret_cast(&ptr_); + } + Iterator& operator++() // pre-increment + { + ptr_ = ptr_->next; + return *this; + } + Iterator operator++(int) // post-increment + { + Iterator tmp = *this; + ++*this; + return tmp; + } + Iterator& operator--() // pre-decrement + { + ptr_ = ptr_->prev; + return *this; + } + Iterator operator--(int) // post-decrement + { + Iterator tmp = *this; + --*this; + return tmp; + } + bool operator==(const Iterator& other) const + { + return ptr_ == other.ptr_; + } + bool operator!=(const Iterator& other) const + { + return ptr_ != other.ptr_; + } + + private: + queue* ptr_{nullptr}; + }; + //friend class Iterator; + + class ConstIterator + { + public: + using iterator_category = std::bidirectional_iterator_tag; + using value_type = T*; + using difference_type = std::ptrdiff_t; + using pointer = const T** ; + using reference = const T* &; + + ConstIterator() = default; + explicit ConstIterator(const queue* p) : ptr_{p} {} + + reference operator*() + { + return reinterpret_cast(ptr_); + } + pointer operator->() + { + return reinterpret_cast(&ptr_); + } + ConstIterator& operator++() // pre-increment + { + ptr_ = ptr_->next; + return *this; + } + ConstIterator operator++(int) // post-increment + { + ConstIterator tmp = *this; + ++*this; + return tmp; + } + ConstIterator& operator--() // pre-decrement + { + ptr_ = ptr_->prev; + return *this; + } + ConstIterator operator--(int) // post-decrement + { + ConstIterator tmp = *this; + --*this; + return tmp; + } + bool operator==(const ConstIterator& other) const + { + return ptr_ == other.ptr_; + } + bool operator!=(const ConstIterator& other) const + { + return ptr_ != other.ptr_; + } + + private: + const queue* ptr_{nullptr}; + }; + //friend class ConstIterator; + + Iterator begin() + { + return Iterator(head_->next); + } + ConstIterator begin() const + { + return ConstIterator(head_->next); + } + Iterator end() + { + return Iterator(head_); + } + ConstIterator end() const + { + return ConstIterator(head_); + } + ConstIterator cbegin() + { + return ConstIterator(head_->next); + } + ConstIterator cend() + { + return ConstIterator(head_); + } + + bool empty() const + { + return begin() == end(); + } + + T& front() + { + return reinterpret_cast(**begin()); + } + + const T& front() const + { + return reinterpret_cast(**begin()); + } + + T& back() + { + auto tmp = end(); + --tmp; + return reinterpret_cast(**tmp); + } + + const T& back() const + { + auto tmp = end(); + --tmp; + return reinterpret_cast(**tmp); + } + +private: + queue* head_; + int* ct_; +}; + + /* * The following sorting code was derived from linked-list mergesort * sample code by Simon Tatham, code obtained from: diff --git a/route.cc b/route.cc index 3707dfb66..62ac2b429 100644 --- a/route.cc +++ b/route.cc @@ -18,116 +18,93 @@ */ #include "defs.h" -#include "grtcirc.h" -#include "session.h" -#include - -queue my_route_head; -queue my_track_head; -static int rte_head_ct; -static int rte_waypts; -static int trk_head_ct; -static int trk_waypts; +#include "grtcirc.h" // for RAD, gcdist, heading_true_degrees, radtometers +#include "queue.h" // for queue, dequeue, QUEUE_FOR_EACH, QUEUE_MOVE, QUEUE_INIT, sortqueue, ENQUEUE_TAIL, QUEUE_EMPTY, ENQUEUE_AFTER, ENQUEUE_HEAD, QUEUE_LAST, QUEUE_NEXT, QueueList +#include "session.h" // for curr_session, session_t (ptr only) +#include "src/core/datetime.h" // for DateTime +#include "src/core/optional.h" // for optional, operator>, operator< +#include // for QDateTime +#include // for QString +#include // for nullptr_t + +RouteList* global_route_list; +RouteList* global_track_list; extern void update_common_traits(const Waypoint* wpt); void route_init() { - QUEUE_INIT(&my_route_head); - QUEUE_INIT(&my_track_head); + global_route_list = new RouteList; + global_track_list = new RouteList; } unsigned int route_waypt_count() { - /* total wapoint count -- all routes */ - return rte_waypts; + /* total waypoint count -- all routes */ + return global_route_list->waypt_count(); } unsigned int route_count() { - return rte_head_ct; /* total # of routes */ + return global_route_list->count(); /* total # of routes */ } unsigned int track_waypt_count() { - /* totaly waypoint count -- all tracks */ - return trk_waypts; + /* total waypoint count -- all tracks */ + return global_track_list->waypt_count(); } unsigned int track_count() { - return trk_head_ct; /* total # of tracks */ + return global_track_list->count(); /* total # of tracks */ } +// FIXME: provide a method to deallocate a head that isn't added onto a route list, +// or just let the users allocate with new and deallocate with delete. route_head* route_head_alloc() { - route_head* rte_head = new route_head; - return rte_head; -} - -static void -any_route_free(route_head* rte) -{ - delete rte; - rte = nullptr; -} - -static void -any_route_add_head(route_head* rte, queue* head) -{ - ENQUEUE_TAIL(head, &rte->Q); -} - -static void -any_route_del_head(route_head* rte) -{ - dequeue(&rte->Q); - any_route_free(rte); + return new route_head; } void route_add_head(route_head* rte) { - any_route_add_head(rte, &my_route_head); - rte_head_ct++; + global_route_list->add_head(rte); } void route_del_head(route_head* rte) { - rte_waypts -= rte->rte_waypt_ct; - any_route_del_head(rte); - rte_head_ct--; + global_route_list->del_head(rte); } void track_add_head(route_head* rte) { - any_route_add_head(rte, &my_track_head); - trk_head_ct++; + global_track_list->add_head(rte); } void track_del_head(route_head* rte) { - trk_waypts -= rte->rte_waypt_ct; - any_route_del_head(rte); - trk_head_ct--; + global_track_list->del_head(rte); } void track_insert_head(route_head* rte, route_head* predecessor) { - ENQUEUE_AFTER(&predecessor->Q, &rte->Q); - trk_head_ct++; + global_track_list->insert_head(rte, predecessor); } +// FIXME: can we delete this unused and untested code? +#ifdef DEAD_CODE_IS_REBORN static route_head* common_route_by_name(queue* routes, const char* name) @@ -135,7 +112,7 @@ common_route_by_name(queue* routes, const char* name) queue* elem, *tmp; QUEUE_FOR_EACH(routes, elem, tmp) { - route_head* rte = reinterpret_cast(elem); + route_head* rte = reinterpret_cast(elem); if (rte->rte_name == name) { return rte; } @@ -155,24 +132,10 @@ route_find_track_by_name(const char* name) { return common_route_by_name(&my_track_head, name); } - -static void -any_route_add_wpt(route_head* rte, Waypoint* wpt, int* ct, int synth, const QString& namepart, int number_digits) -{ - ENQUEUE_TAIL(&rte->waypoint_list, &wpt->Q); - rte->rte_waypt_ct++; /* waypoints in this route */ - if (ct) { - (*ct)++; - } - if (synth && wpt->shortname.isEmpty()) { - wpt->shortname = QString().sprintf("%s%0*d", CSTRc(namepart), number_digits, *ct); - wpt->wpt_flags.shortname_is_synthetic = 1; - } - update_common_traits(wpt); -} +#endif void -route_add_wpt_named(route_head* rte, Waypoint* wpt, const QString& namepart, int number_digits) +route_add_wpt(route_head* rte, Waypoint* wpt, const QString& namepart, int number_digits) { // First point in a route is always a new segment. // This improves compatibility when reading from @@ -181,18 +144,11 @@ route_add_wpt_named(route_head* rte, Waypoint* wpt, const QString& namepart, int wpt->wpt_flags.new_trkseg = 1; } - any_route_add_wpt(rte, wpt, &rte_waypts, 1, namepart, number_digits); + global_route_list->add_wpt(rte, wpt, true, namepart, number_digits); } void -route_add_wpt(route_head* rte, Waypoint* wpt) -{ - const char RPT[] = "RPT"; - route_add_wpt_named(rte, wpt, RPT, 3); -} - -void -track_add_wpt_named(route_head* rte, Waypoint* wpt, const QString& namepart, int number_digits) +track_add_wpt(route_head* rte, Waypoint* wpt, const QString& namepart, int number_digits) { // First point in a track is always a new segment. // This improves compatibility when reading from @@ -201,55 +157,38 @@ track_add_wpt_named(route_head* rte, Waypoint* wpt, const QString& namepart, int wpt->wpt_flags.new_trkseg = 1; } - any_route_add_wpt(rte, wpt, &trk_waypts, 0, namepart, number_digits); -} - -void -track_add_wpt(route_head* rte, Waypoint* wpt) -{ - const char RPT[] = "RPT"; - track_add_wpt_named(rte, wpt, RPT, 3); + // FIXME: It is misleading to accept namepart and number_digits parameters which + // are ignored because synth is set to false. + global_track_list->add_wpt(rte, wpt, false, namepart, number_digits); } +// FIXME: can we delete this unused and untested code? +#ifdef DEAD_CODE_IS_REBORN Waypoint* route_find_waypt_by_name(route_head* rh, const char* name) { queue* elem, *tmp; QUEUE_FOR_EACH(&rh->waypoint_list, elem, tmp) { - Waypoint* waypointp = reinterpret_cast(elem); + Waypoint* waypointp = reinterpret_cast(elem); if (waypointp->shortname == name) { return waypointp; } } return nullptr; } - -static void -any_route_del_wpt(route_head* rte, Waypoint* wpt, int* ct) -{ - if (wpt->wpt_flags.new_trkseg && wpt != reinterpret_castQUEUE_LAST(&rte->waypoint_list)) { - Waypoint* wpt_next = reinterpret_castQUEUE_NEXT(&wpt->Q); - wpt_next->wpt_flags.new_trkseg = 1; - } - wpt->wpt_flags.new_trkseg = 0; - dequeue(&wpt->Q); - rte->rte_waypt_ct--; - if (ct) { - (*ct)--; - } -} +#endif void route_del_wpt(route_head* rte, Waypoint* wpt) { - any_route_del_wpt(rte, wpt, &rte_waypts); + global_route_list->del_wpt(rte, wpt); } void track_del_wpt(route_head* rte, Waypoint* wpt) { - any_route_del_wpt(rte, wpt, &trk_waypts); + global_track_list->del_wpt(rte, wpt); } void @@ -262,220 +201,107 @@ void route_reverse(const route_head* rte_hd) { /* Cast away const-ness */ - route_head* rh = const_cast(rte_hd); + auto rh = const_cast(rte_hd); queue* elem, *tmp; QUEUE_FOR_EACH(&rh->waypoint_list, elem, tmp) { ENQUEUE_HEAD(&rh->waypoint_list, dequeue(elem)); } } -static void -common_disp_session(const session_t* se, queue* qh, route_hdr rh, route_trl rt, waypt_cb wc) -{ - queue* elem, *tmp; - QUEUE_FOR_EACH(qh, elem, tmp) { - const route_head* rhp = reinterpret_cast(elem); - if (rhp->session == se) { - if (rh) { - (*rh)(rhp); - } - route_disp(rhp, wc); - if (rt) { - (*rt)(rhp); - } - } - } -} - void route_disp_session(const session_t* se, route_hdr rh, route_trl rt, waypt_cb wc) { - common_disp_session(se, &my_route_head, rh, rt, wc); + global_route_list->common_disp_session(se, rh, rt, wc); } void track_disp_session(const session_t* se, route_hdr rh, route_trl rt, waypt_cb wc) { - common_disp_session(se, &my_track_head, rh, rt, wc); -} - -static void -route_flush_q(queue* head) -{ - queue* elem, *tmp; - - QUEUE_FOR_EACH(head, elem, tmp) { - queue* q = dequeue(elem); - any_route_free(reinterpret_cast(q)); - } + global_track_list->common_disp_session(se, rh, rt, wc); } void route_flush_all_routes() { - route_flush_q(&my_route_head); - rte_head_ct = 0; - rte_waypts = 0; + global_route_list->flush(); } void route_flush_all_tracks() { - route_flush_q(&my_track_head); - trk_head_ct = 0; - trk_waypts = 0; + global_track_list->flush(); } void -route_flush_all() +route_deinit() { - route_flush_all_tracks(); route_flush_all_routes(); + route_flush_all_tracks(); + delete global_route_list; + delete global_track_list; } void -route_flush(queue* head) +route_append(RouteList* src) { - queue* elem, *tmp; - QUEUE_FOR_EACH(head, elem, tmp) { - queue* q = dequeue(elem); - any_route_free(reinterpret_cast(q)); - } + src->copy(&global_route_list); } void -route_copy(int* dst_count, int* dst_wpt_count, queue** dst, queue* src) +track_append(RouteList* src) { - queue* elem, *tmp, *elem2, *tmp2; - int junk; - if (!dst_wpt_count) { - dst_wpt_count = &junk; - } - - if (!*dst) { - *dst = (queue*)xcalloc(1, sizeof(queue)); - QUEUE_INIT(*dst); - *dst_count = 0; - *dst_wpt_count = 0; - } - - const char RPT[] = "RPT"; - QUEUE_FOR_EACH(src, elem, tmp) { - route_head* rte_old = reinterpret_cast(elem); - - route_head* rte_new = route_head_alloc(); - rte_new->rte_name = rte_old->rte_name; - rte_new->rte_desc = rte_old->rte_desc; - rte_new->rte_urls = rte_old->rte_urls; - rte_new->fs = fs_chain_copy(rte_old->fs); - rte_new->rte_num = rte_old->rte_num; - any_route_add_head(rte_new, *dst); - QUEUE_FOR_EACH(&rte_old->waypoint_list, elem2, tmp2) { - any_route_add_wpt(rte_new, new Waypoint(*reinterpret_cast(elem2)), dst_wpt_count, 0, RPT, 3); - } - (*dst_count)++; - } + src->copy(&global_track_list); } void -route_append(queue* src) +route_backup(RouteList** head_bak) { - queue* dst = &my_route_head; - route_copy(&rte_head_ct, &rte_waypts, &dst, src); + global_route_list->copy(head_bak); } void -track_append(queue* src) +route_restore(RouteList* head_bak) { - queue* dst = &my_track_head; - route_copy(&trk_head_ct, &trk_waypts, &dst, src); + global_route_list->restore(head_bak); } void -route_backup(signed int* count, queue** head_bak) -{ - route_copy(count, nullptr, head_bak, &my_route_head); -} - -static void -route_restore_hdr(const route_head* rte) -{ - (void)rte; - rte_head_ct++; -} - -static void -track_restore_hdr(const route_head* trk) -{ - (void)trk; - trk_head_ct++; -} - -static void -route_restore_tlr(const route_head* rte) -{ - (void)rte; -} - -static void -route_restore_wpt(const Waypoint* wpt) +route_swap(RouteList& other) { - (void)wpt; - rte_waypts++; + global_route_list->swap(other); } -static void -track_restore_wpt(const Waypoint* wpt) +void +route_sort(RouteList::Compare cmp) { - (void)wpt; - trk_waypts++; + global_route_list->sort(cmp); } -static void -common_restore_finish() +void +track_backup(RouteList** head_bak) { - rte_head_ct = 0; - trk_head_ct = 0; - rte_waypts = 0; - trk_waypts = 0; - route_disp_all(route_restore_hdr, route_restore_tlr, route_restore_wpt); - track_disp_all(track_restore_hdr, route_restore_tlr, track_restore_wpt); + global_track_list->copy(head_bak); } void -route_restore(queue* head_bak) +track_restore(RouteList* head_bak) { - if (head_bak == nullptr) { - return; - } - - route_flush_q(&my_route_head); - QUEUE_INIT(&my_route_head); - QUEUE_MOVE(&my_route_head, head_bak); - - common_restore_finish(); + global_track_list->restore(head_bak); } void -track_backup(signed int* count, queue** head_bak) +track_swap(RouteList& other) { - route_copy(count, nullptr, head_bak, &my_track_head); + global_track_list->swap(other); } void -track_restore(queue* head_bak) +track_sort(RouteList::Compare cmp) { - if (head_bak == nullptr) { - return; - } - - route_flush_q(&my_track_head); - QUEUE_INIT(&my_track_head); - QUEUE_MOVE(&my_track_head, head_bak); - - common_restore_finish(); + global_track_list->sort(cmp); } +// FIXME: can we delete this unused and untested code? #ifdef DEAD_CODE_IS_REBORN /* * Move the entire track queue onto the route queue making no attempt @@ -494,6 +320,7 @@ routes_to_tracks() } #endif +// FIXME: can we delete this unused and untested code? #ifdef DEAD_CODE_IS_REBORN /* * Same, but in opposite direction. @@ -536,8 +363,8 @@ computed_trkdata track_recompute(const route_head* trk) // first.longitude = 0; // first.creation_time = 0; - QUEUE_FOR_EACH((queue*)&trk->waypoint_list, elem, tmp) { - Waypoint* thisw = reinterpret_cast(elem); + QUEUE_FOR_EACH(&trk->waypoint_list, elem, tmp) { + auto thisw = reinterpret_cast(elem); /* * gcdist and heading want radians, not degrees. @@ -661,3 +488,170 @@ route_head::~route_head() fs_chain_destroy(fs); } } + +RouteList::RouteList() : QueueList(&head, &head_ct) +{ + QUEUE_INIT(&head); +} + +int RouteList::count() const +{ + return head_ct; +} + +int RouteList::waypt_count() const +{ + return waypt_ct; +} + +// rte may or may not contain waypoints in it's waypoint_list. +// FIXME: In the case that it does, our count of total waypoints won't +// match until after rte is added. +// examples are in tests for garmin_txt, gdb, ggv_log, ik3d, navitel, osm. +void +RouteList::add_head(route_head* rte) +{ + ENQUEUE_TAIL(&head, &rte->Q); + ++head_ct; +} + +void +RouteList::del_head(route_head* rte) +{ + waypt_ct -= rte->rte_waypt_ct; + dequeue(&rte->Q); + delete rte; + --head_ct; +} + +void +RouteList::insert_head(route_head* rte, route_head* predecessor) +{ + ENQUEUE_AFTER(&predecessor->Q, &rte->Q); + ++head_ct; +} + +// Synthesizing names based on the total number of waypoints in the RouteList makes +// it advantageous to keep a count of the total number of waypoints in all the routes +// in the RouteList AND any routes that have had waypoints added but haven't been +// added themselves yet. +void +RouteList::add_wpt(route_head* rte, Waypoint* wpt, bool synth, const QString& namepart, int number_digits) +{ + ENQUEUE_TAIL(&rte->waypoint_list, &wpt->Q); + rte->rte_waypt_ct++; /* waypoints in this route */ + ++waypt_ct; + if (synth && wpt->shortname.isEmpty()) { + wpt->shortname = QString().sprintf("%s%0*d", CSTRc(namepart), number_digits, waypt_ct); + wpt->wpt_flags.shortname_is_synthetic = 1; + } + update_common_traits(wpt); +} + +void +RouteList::del_wpt(route_head* rte, Waypoint* wpt) +{ + if (wpt->wpt_flags.new_trkseg && wpt != reinterpret_castQUEUE_LAST(&rte->waypoint_list)) { + auto wpt_next = reinterpret_castQUEUE_NEXT(&wpt->Q); + wpt_next->wpt_flags.new_trkseg = 1; + } + wpt->wpt_flags.new_trkseg = 0; + dequeue(&wpt->Q); + rte->rte_waypt_ct--; + --waypt_ct; +} + +void +RouteList::common_disp_session(const session_t* se, route_hdr rh, route_trl rt, waypt_cb wc) +{ + queue* elem, *tmp; + QUEUE_FOR_EACH(&head, elem, tmp) { + const route_head* rhp = reinterpret_cast(elem); + if (rhp->session == se) { + if (rh) { + (*rh)(rhp); + } + route_disp(rhp, wc); + if (rt) { + (*rt)(rhp); + } + } + } +} + +void +RouteList::flush() +{ + queue* elem, *tmp; + + QUEUE_FOR_EACH(&head, elem, tmp) { + queue* q = dequeue(elem); + delete reinterpret_cast(q); + } + head_ct = 0; + waypt_ct = 0; +} + +void +RouteList::copy(RouteList** dst) const +{ + queue* elem, *tmp, *elem2, *tmp2; + + if (*dst == nullptr) { + *dst = new RouteList; + } + + const char RPT[] = "RPT"; + QUEUE_FOR_EACH(&head, elem, tmp) { + auto rte_old = reinterpret_cast(elem); + + route_head* rte_new = route_head_alloc(); + rte_new->rte_name = rte_old->rte_name; + rte_new->rte_desc = rte_old->rte_desc; + rte_new->rte_urls = rte_old->rte_urls; + rte_new->fs = fs_chain_copy(rte_old->fs); + rte_new->rte_num = rte_old->rte_num; + (*dst)->add_head(rte_new); + QUEUE_FOR_EACH(&rte_old->waypoint_list, elem2, tmp2) { + (*dst)->add_wpt(rte_new, new Waypoint(*reinterpret_cast(elem2)), false, RPT, 3); + } + } +} + +void +RouteList::restore(RouteList* src) +{ + if (src == nullptr) { + return; + } + + flush(); + QUEUE_MOVE(&head, &src->head); + + head_ct = src->head_ct; + src->head_ct = 0; + waypt_ct = src->waypt_ct; + src->waypt_ct = 0; +} + +void RouteList::swap(RouteList& other) +{ + queue tmp_head; + QUEUE_MOVE(&tmp_head, &(other.head)); + QUEUE_MOVE(&(other.head), &(this->head)); + QUEUE_MOVE(&(this->head), &tmp_head); + + const auto tmp_head_ct = other.head_ct; + other.head_ct = this->head_ct; + this->head_ct = tmp_head_ct; + + const auto tmp_waypt_ct = other.waypt_ct; + other.waypt_ct = this->waypt_ct; + this->waypt_ct = tmp_waypt_ct; +} + +void RouteList::sort(Compare cmp) +{ + sortqueue(&head, cmp); +} + diff --git a/sort.cc b/sort.cc index c4242bc3f..1f28e243e 100644 --- a/sort.cc +++ b/sort.cc @@ -24,10 +24,8 @@ #include // for QString #include // for abort -extern queue my_route_head; -extern queue my_track_head; - #if FILTERS_ENABLED +#define MYNAME "sort" template inline int sgn(T v) @@ -64,49 +62,71 @@ int SortFilter::sort_comp_wpt(const queue* a, const queue* b) } } -int SortFilter::sort_comp_rh(const queue* a, const queue* b) +int SortFilter::sort_comp_rh_by_description(const queue* a, const queue* b) { const route_head* x1 = reinterpret_cast(a); const route_head* x2 = reinterpret_cast(b); - switch (rh_sort_mode) { - case SortModeRteHd::description: - return x1->rte_desc.compare(x2->rte_desc); - case SortModeRteHd::name: - return x1->rte_name.compare(x2->rte_name); - case SortModeRteHd::number: - return cmp(x1->rte_num, x2->rte_num); - default: - abort(); - return 0; /* Internal caller error. */ - } + return x1->rte_desc.compare(x2->rte_desc); } -int SortFilter::SortCompWptFunctor::operator()(const queue* a, const queue* b) +int SortFilter::sort_comp_rh_by_name(const queue* a, const queue* b) { - return that->sort_comp_wpt(a, b); + const route_head* x1 = reinterpret_cast(a); + const route_head* x2 = reinterpret_cast(b); + + return x1->rte_name.compare(x2->rte_name); } -int SortFilter::SortCompRteHdFunctor::operator()(const queue* a, const queue* b) +int SortFilter::sort_comp_rh_by_number(const queue* a, const queue* b) { - return that->sort_comp_rh(a, b); + const route_head* x1 = reinterpret_cast(a); + const route_head* x2 = reinterpret_cast(b); + + return cmp(x1->rte_num, x2->rte_num); +} + +int SortFilter::SortCompWptFunctor::operator()(const queue* a, const queue* b) +{ + return that->sort_comp_wpt(a, b); } void SortFilter::process() { SortCompWptFunctor sort_comp_wpt_f(*this); - SortCompRteHdFunctor sort_comp_rh_f(*this); if (wpt_sort_mode != SortModeWpt::none) { sortqueue(&waypt_head, sort_comp_wpt_f); } if (rte_sort_mode != SortModeRteHd::none) { - rh_sort_mode = rte_sort_mode; - sortqueue(&my_route_head, sort_comp_rh_f); + switch (rte_sort_mode) { + case SortModeRteHd::description: + route_sort(SortFilter::sort_comp_rh_by_description); + break; + case SortModeRteHd::name: + route_sort(sort_comp_rh_by_name); + break; + case SortModeRteHd::number: + route_sort(sort_comp_rh_by_number); + break; + default: + fatal(MYNAME ": unknown route sort mode."); + } } if (trk_sort_mode != SortModeRteHd::none) { - rh_sort_mode = trk_sort_mode; - sortqueue(&my_track_head, sort_comp_rh_f); + switch (trk_sort_mode) { + case SortModeRteHd::description: + track_sort(sort_comp_rh_by_description); + break; + case SortModeRteHd::name: + track_sort(sort_comp_rh_by_name); + break; + case SortModeRteHd::number: + track_sort(sort_comp_rh_by_number); + break; + default: + fatal(MYNAME ": unknown track sort mode."); + } } } diff --git a/sort.h b/sort.h index 8bf31b6f0..9e42f7cf4 100644 --- a/sort.h +++ b/sort.h @@ -58,7 +58,6 @@ private: SortModeRteHd rte_sort_mode = SortModeRteHd::none; /* How are we sorting these? */ SortModeRteHd trk_sort_mode = SortModeRteHd::none; /* How are we sorting these? */ - SortModeRteHd rh_sort_mode = SortModeRteHd::none; char* opt_sm_gcid, *opt_sm_shortname, *opt_sm_description, *opt_sm_time; char* opt_sm_rtenum, *opt_sm_rtename, *opt_sm_rtedesc; @@ -109,7 +108,9 @@ private: }; int sort_comp_wpt(const queue* a, const queue* b); - int sort_comp_rh(const queue* a, const queue* b); + static int sort_comp_rh_by_description(const queue* a, const queue* b); + static int sort_comp_rh_by_name(const queue* a, const queue* b); + static int sort_comp_rh_by_number(const queue* a, const queue* b); class SortCompWptFunctor { @@ -121,16 +122,6 @@ private: SortFilter* that; }; - class SortCompRteHdFunctor - { - public: - explicit SortCompRteHdFunctor(SortFilter& obj) : that(&obj) {} - int operator()(const queue* a, const queue* b); - - private: - SortFilter* that; - }; - }; #endif // FILTERS_ENABLED #endif // SORT_H_INCLUDED_ diff --git a/stackfilter.cc b/stackfilter.cc index 9e79d3e22..c50f5445d 100644 --- a/stackfilter.cc +++ b/stackfilter.cc @@ -30,13 +30,14 @@ void StackFilter::process() { - struct stack_elt* tmp_elt = nullptr; + stack_elt* tmp_elt = nullptr; queue* elem = nullptr; queue* tmp = nullptr; queue tmp_queue; + RouteList* route_list_ptr; if (opt_push) { - tmp_elt = (struct stack_elt*)xmalloc(sizeof(struct stack_elt)); + tmp_elt = new stack_elt; QUEUE_MOVE(&(tmp_elt->waypts), &waypt_head); tmp_elt->waypt_ct = waypt_count(); @@ -49,18 +50,14 @@ void StackFilter::process() } } - tmp = nullptr; - route_backup(&(tmp_elt->route_count), &tmp); - QUEUE_MOVE(&(tmp_elt->routes), tmp); - xfree(tmp); + route_list_ptr = &(tmp_elt->routes); + route_backup(&route_list_ptr); if (!opt_copy) { route_flush_all_routes(); } - tmp = nullptr; - track_backup(&(tmp_elt->track_count), &tmp); - QUEUE_MOVE(&(tmp_elt->tracks), tmp); - xfree(tmp); + route_list_ptr = &(tmp_elt->tracks); + track_backup(&route_list_ptr); if (!opt_copy) { route_flush_all_tracks(); } @@ -75,13 +72,13 @@ void StackFilter::process() waypt_add(reinterpret_cast(elem)); } route_append(&(stack->routes)); - route_flush(&(stack->routes)); + stack->routes.flush(); track_append(&(stack->tracks)); - route_flush(&(stack->tracks)); + stack->tracks.flush(); } else if (opt_discard) { waypt_flush(&(stack->waypts)); - route_flush(&(stack->routes)); - route_flush(&(stack->tracks)); + stack->routes.flush(); + stack->tracks.flush(); } else { waypt_flush(&waypt_head); QUEUE_MOVE(&(waypt_head), &(stack->waypts)); @@ -92,7 +89,7 @@ void StackFilter::process() } stack = tmp_elt->next; - xfree(tmp_elt); + delete tmp_elt; } else if (opt_swap) { tmp_elt = stack; while (swapdepth > 1) { @@ -105,24 +102,13 @@ void StackFilter::process() QUEUE_MOVE(&tmp_queue, &(tmp_elt->waypts)); QUEUE_MOVE(&(tmp_elt->waypts), &waypt_head); QUEUE_MOVE(&waypt_head, &tmp_queue); - - QUEUE_MOVE(&tmp_queue, &(tmp_elt->routes)); - tmp = nullptr; - route_backup(&(tmp_elt->route_count), &tmp); - QUEUE_MOVE(&(tmp_elt->routes), tmp); - xfree(tmp); - route_restore(&tmp_queue); - - QUEUE_MOVE(&tmp_queue, &(tmp_elt->tracks)); - tmp = nullptr; - track_backup(&(tmp_elt->track_count), &tmp); - QUEUE_MOVE(&(tmp_elt->tracks), tmp); - xfree(tmp); - track_restore(&tmp_queue); - unsigned int tmp_count = waypt_count(); set_waypt_count(tmp_elt->waypt_ct); tmp_elt->waypt_ct = tmp_count; + + route_swap(tmp_elt->routes); + + track_swap(tmp_elt->tracks); } } @@ -172,7 +158,7 @@ void StackFilter::deinit() void StackFilter::exit() { - struct stack_elt* tmp_elt = nullptr; + stack_elt* tmp_elt = nullptr; if (warnings_enabled && stack) { warning(MYNAME " Warning: leftover stack entries; " @@ -182,7 +168,7 @@ void StackFilter::exit() waypt_flush(&(stack->waypts)); tmp_elt = stack; stack = stack->next; - xfree(tmp_elt); + delete tmp_elt; } } diff --git a/stackfilter.h b/stackfilter.h index 798a52f16..2e88cd785 100644 --- a/stackfilter.h +++ b/stackfilter.h @@ -93,15 +93,21 @@ private: ARG_TERMINATOR }; - struct stack_elt { + class stack_elt + { + public: + stack_elt() + { + QUEUE_INIT(&waypts); + } + queue waypts; - queue routes; - queue tracks; - unsigned int waypt_ct; - int route_count; - int track_count; - struct stack_elt* next; - }* stack = nullptr; + RouteList routes; + RouteList tracks; + unsigned int waypt_ct{0}; + stack_elt* next{nullptr}; + }; + stack_elt* stack = nullptr; }; #endif // FILTERS_ENABLED diff --git a/transform.cc b/transform.cc index e5d563f70..6cadb9358 100644 --- a/transform.cc +++ b/transform.cc @@ -53,10 +53,10 @@ void TransformFilter::transform_waypoints() wpt = new Waypoint(*wpt); switch (current_target) { case 'R': - route_add_wpt_named(rte, wpt, RPT, name_digits); + route_add_wpt(rte, wpt, RPT, name_digits); break; case 'T': - track_add_wpt_named(rte, wpt, RPT, name_digits); + track_add_wpt(rte, wpt, RPT, name_digits); break; } } @@ -99,9 +99,9 @@ void TransformFilter::transform_any_disp_wpt_cb(const Waypoint* wpt) { Waypoint* temp = new Waypoint(*wpt); if (current_target == 'R') { - route_add_wpt_named(current_rte, temp, current_namepart, name_digits); + route_add_wpt(current_rte, temp, current_namepart, name_digits); } else if (current_target == 'T') { - track_add_wpt_named(current_trk, temp, current_namepart, name_digits); + track_add_wpt(current_trk, temp, current_namepart, name_digits); } else { waypt_add(temp); }